home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_503 / pcq / pcq12asc.lzh / Source / IO.p < prev    next >
Text File  |  1991-05-13  |  24KB  |  1,133 lines

  1. External;
  2.  
  3. {
  4.     IO.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid
  6.  
  7.     This module handles the IO of the compiler.  The actual
  8. compilation of the io statements is handled in stanprocs.p
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include:Libraries/DOS.i" }
  14. {$I "Include:Utils/StringLib.i"}
  15. {$I "Include:Utils/Break.i"}
  16.  
  17.  
  18.     Procedure Out_Operation1(op : OpCodes; Size : Byte;
  19.                     EA : EAModes; Reg : Regs);
  20.         External;
  21.     Procedure Out_Extension(Ext : Integer);
  22.         External;
  23.  
  24. Function EndOfFile() : Boolean;
  25.  
  26. {
  27.     This just determines when the end of all input has occured.
  28. }
  29.  
  30. begin
  31.     EndOfFile := (InFile = nil) and (not CharBuffed);
  32. end;
  33.  
  34. Procedure AnnounceFile;
  35. begin
  36.     if StdOut_Interactive then
  37.     Write('\r\cK', LineNo:5, ' ', InFile^.Name, '\r');
  38. end;
  39.  
  40. Procedure WriteLineNo;
  41. begin
  42.     if StdOut_Interactive then
  43.     Write(Chr(13), LineNo:5);
  44. end;
  45.  
  46. Procedure CountLines;
  47.  
  48. { Does the bookkeeping for errors }
  49.  
  50. begin
  51.     if CurrentChar = Chr(10) then begin
  52.     LineNo := Succ(LineNo);
  53.     if Inform then
  54.         if (LineNo and 15) = 0 then
  55.         WriteLineNo;
  56.     end;
  57. end;
  58.  
  59. Procedure EndComment;
  60.     forward;    { It's in this module }
  61.  
  62. Procedure CloseInputFile;
  63.  
  64. { This closes the current input file and restores the saved stuff }
  65.  
  66. var
  67.     TempPtr : FileRecPtr;
  68.     Result  : Short;
  69. begin
  70.     if Inform and StdOut_Interactive then begin
  71.     WriteLineNo;
  72.     Writeln;
  73.     end;
  74.     Close(InFile^.PCQFile);
  75.     Result := IOResult;
  76.     TempPtr := InFile^.Previous;
  77.     FreeString(InFile^.Name);
  78.     Dispose(InFile);
  79.     InFile := TempPtr;
  80.     if InFile <> nil then begin
  81.     LineNo := InFile^.SaveLine;
  82.     FNStart := InFile^.SaveStart;
  83.     CurrentChar := InFile^.SaveChar;
  84.     if Inform then
  85.         AnnounceFile;
  86.     EndComment;
  87.     end else
  88.     CurrentChar := Chr(0);
  89. end;
  90.  
  91. Procedure Abort;
  92.  
  93. {
  94.     This routine cuts out cleanly.  If you are debugging the
  95. compiler, this is a likely place to put post mortem dumps, like the
  96. one commented out.
  97. }
  98. var
  99.     Result : Short;
  100. begin
  101.     While InFile <> nil do
  102.     CloseInputFile;
  103.     Close(OutFile);
  104.     Result := IOResult;
  105.     Writeln('Compilation Aborted');
  106.     Exit(20);
  107. end;
  108.  
  109. Function OpenInputFile(name : String) : Boolean;
  110.  
  111. { This routine opens a new file record, and a new file.  It also
  112.   saves the state of the File-dependant variables, like LineNo. }
  113.  
  114. var
  115.     TempPtr : FileRecPtr;
  116.     OpenError : Integer;
  117. begin
  118.     New(TempPtr);
  119.     if not ReOpen(name, TempPtr^.PCQFile, 10240) then begin
  120.     Dispose(TempPtr);
  121.     OpenError := IOResult;
  122.     OpenInputFile := False;
  123.     end;
  124.     TempPtr^.Previous := InFile;
  125.     if InFile <> nil then begin
  126.     InFile^.SaveLine := LineNo;
  127.     InFile^.SaveStart := FNStart;
  128.     InFile^.SaveChar  := CurrentChar;
  129.     end;
  130.     LineNo := 1;
  131.     FNStart := 1;
  132.     TempPtr^.Name := strdup(name);
  133.     InFile := TempPtr;
  134.     if EOF(InFile^.PCQFile) then
  135.     CloseInputFile
  136.     else
  137.     Read(Infile^.PCQFile, CurrentChar);
  138.     if Inform then
  139.     AnnounceFile;
  140.     OpenInputFile := True;
  141. end;
  142.  
  143. Function EQFix(x : Short) : Integer;
  144.  
  145. {
  146.     This helps implement a queue.  In this case it's for the
  147. error queue.
  148. }
  149.  
  150. begin
  151.     EQFix := x and EQSize;
  152. end;
  153.  
  154. Procedure Error(ptr : string);
  155.  
  156. {
  157.     This just writes out at most the previous 128 characters or
  158. two lines, then writes the error message passed to it.  If there
  159. are five errors, it aborts.
  160. }
  161.  
  162. var
  163.     index : integer;
  164.     newlines : integer;
  165.     Column : Short;
  166.     LessLines : Short;
  167. begin
  168.     index     := EQEnd;
  169.     newlines  := 0;
  170.     Column    := 0;
  171.     LessLines := 0;
  172.  
  173.     while (index <> EQStart) and (newlines < 2) do begin
  174.     if Index = ErrorPtr then begin
  175.         Column := 1;
  176.         LessLines := NewLines;
  177.     end else if LessLines = NewLines then
  178.         Inc(Column);
  179.  
  180.     index := EQFix(index - 1);
  181.     if ErrorQ[EQFix(index - 1)] = chr(10) then
  182.         Inc(NewLines);
  183.     end;
  184.  
  185.     if CurrentChar = Chr(10) then
  186.     Inc(LessLines);
  187.  
  188.     if Inform then begin
  189.     if StdOut_Interactive then
  190.         write('\n\cK'); { newline, ClrEOL }
  191.     while index <> EQEnd do begin
  192.         if (index = ErrorPtr) and StdOut_Interactive then
  193.         write('\c0;33;40m');  { start highlight for ANSI }
  194.         write(ErrorQ[index]);
  195.         index := EQFix(index + 1);
  196.     end;
  197.     if StdOut_Interactive then
  198.         write('\c0;31;40m');  { end highlight }
  199.     writeln;
  200.     write('Line ', LineNo - LessLines, ' ');
  201.     if currfn <> nil then
  202.         write('(', CurrFn^.Name, ')');
  203.     writeln(': ', ptr, '\n');
  204.     end else
  205.     Writeln('"', InFile^.Name, '" At ', LineNo - LessLines, ',',
  206.         Column, ' : ', ptr);
  207.                  { Quiet mode, no surprises }
  208.  
  209.     Inc(errorcount);
  210.     if errorcount > 3 then
  211.     Abort;
  212.     if CheckBreak() then
  213.     Abort;
  214.     if Inform then
  215.     AnnounceFile;
  216. end;
  217.  
  218. Procedure ReadChar;
  219.  
  220. { This is the main link between the lexical analysis stuff and the
  221.   IO stuff.  It sets up CurrentChar and keeps the line count. }
  222. var
  223.     IOError : Integer;
  224. begin
  225.     if CheckBreak() then
  226.     Abort;
  227.     if CharBuffed then begin
  228.     CurrentChar := BuffedChar;
  229.     CharBuffed := False;
  230.     return;
  231.     end;
  232.     if EOF(InFile^.PCQFile) then
  233.     CloseInputFile
  234.     else begin
  235.     Read(InFile^.PCQFile, CurrentChar);
  236.     IOError := IOResult;
  237.     CountLines;
  238.     end;
  239.     EQEnd := EQFix(Succ(EQEnd));
  240.     ErrorQ[EQEnd] := CurrentChar;
  241.     if EQStart = EQEnd then
  242.     EQStart := EQFix(Succ(EQStart));
  243. end;
  244.  
  245. Function NextChar() : Char;
  246. var
  247.     c : Char;
  248. begin
  249.     if not CharBuffed then begin
  250.     c := CurrentChar;
  251.     ReadChar;
  252.     BuffedChar := CurrentChar;
  253.     CurrentChar := c;
  254.     CharBuffed := True;
  255.     end;
  256.     NextChar := BuffedChar;
  257. end;
  258.  
  259. Procedure EndComment;
  260.  
  261. {
  262.     This just eats characters up to the end of a comment.  If
  263. you want nested comments, this is probably the place to do it.
  264. }
  265.  
  266. begin
  267.     while (Currentchar <> '}') and (not EndOfFile()) do
  268.     ReadChar;
  269.     if not EndOfFile() then
  270.     ReadChar;
  271. end;
  272.  
  273. Function GetLabel() : integer;
  274.  
  275. {
  276.     As in all compilers, this just returns a unique serial
  277. number.
  278. }
  279.  
  280. begin
  281.     Inc(NxtLab);
  282.     getlabel := nxtlab;
  283. end;
  284.  
  285. Procedure PrintLabel(lab : integer);
  286.  
  287. {
  288.     This routine prints a label based on a number from the
  289. above procedure.  The prefix for the label can be anything the
  290. assembler accepts - in this case I wanted it similar to the prefix
  291. of the run time library routines.  I didn't realize how ugly it
  292. would look.
  293. }
  294.  
  295. begin
  296.     write(OutFile, '_p%', lab);
  297. end;
  298.  
  299. Function JustFileName(S : String) : String;
  300.  
  301. { returns a string that is the file name part of a path.  It does
  302.   NOT allocate space. }
  303.  
  304. var
  305.     Ptr : String;
  306. begin
  307.     if S^ = Chr(0) then
  308.     JustFileName := S;
  309.     Ptr := S;
  310.     while Ptr^ <> Chr(0) do
  311.     Inc(Ptr);
  312.     Dec(Ptr);
  313.     while (Ptr^ <> ':') and (Ptr^ <> '/') do begin
  314.     if Ptr = S then
  315.         JustFileName := S;
  316.     Dec(Ptr);
  317.     end;
  318.     Inc(Ptr);
  319.     JustFileName := Ptr;
  320. end;
  321.  
  322. Procedure AddIncludeName(S : String);
  323.  
  324. { Adds the name of an include file to the list, so it won't be
  325.   included again. }
  326.  
  327. var
  328.     Ptr : IncludeRecPtr;
  329. begin
  330.     Ptr := IncludeRecPtr(AllocString(strlen(S) + 5));
  331.     if Ptr = nil then
  332.     Abort;
  333.     strcpy(Adr(Ptr^.Name), S);
  334.     Ptr^.Next := IncludeList;
  335.     IncludeList := Ptr;
  336. end;
  337.  
  338. Function AlreadyIncluded(S : String) : Boolean;
  339.  
  340. { Determines whether a file has been included already }
  341.  
  342. var
  343.     Ptr : IncludeRecPtr;
  344. begin
  345.     Ptr := IncludeList;
  346.     while Ptr <> nil do begin
  347.     if strieq(Adr(Ptr^.Name), S) then
  348.         AlreadyIncluded := True;
  349.     Ptr := Ptr^.Next;
  350.     end;
  351.     AlreadyIncluded := False;
  352. end;
  353.  
  354. Procedure DoInclude;
  355.  
  356. {
  357.     The name says it all.  The mechanics of the include
  358. directive are all handled here.
  359. }
  360.  
  361. var
  362.     Ptr : String;
  363. begin
  364.     ReadChar;
  365.     While (CurrentChar <= ' ') and (not EndOfFile()) do
  366.     ReadChar;
  367.     if CurrentChar <> '"' then begin
  368.     Error("Missing Quote");
  369.     EndComment;
  370.     Return;
  371.     end;
  372.     ReadChar;
  373.     Ptr := SymText;
  374.     while CurrentChar <> '"' do begin
  375.     Ptr^ := CurrentChar;
  376.     Inc(Ptr);
  377.     if EndOfFile() then
  378.         Return;
  379.     ReadChar;
  380.     end;
  381.     Ptr^ := Chr(0); { mark then end of the file name }
  382.     ReadChar;        { read the end quote }
  383.     if not AlreadyIncluded(JustFileName(SymText)) then begin
  384.     if OpenInputFile(SymText) then
  385.         AddIncludeName(JustFileName(SymText))
  386.     else begin
  387.         Error("Could not open input file");
  388.         EndComment;
  389.     end;
  390.     end else
  391.     EndComment;
  392. end;
  393.  
  394. Procedure DoComment;
  395.  
  396. {
  397.     This routine implements compiler directives.
  398. }
  399.  
  400.     Procedure DoASM;
  401.     var
  402.     Buffer : Array [0..127] of Char;
  403.     i      : Byte;
  404.  
  405.     Procedure WriteIt;
  406.     begin
  407.         Buffer[i] := '\0';
  408.         if CurrFn = Nil then
  409.         Writeln(OutFile, String(Adr(Buffer)))
  410.         else begin
  411.         Out_Operation1(op_LABEL,3,ea_String,a7);
  412.         Out_Extension(Integer(strdup(Adr(Buffer))));
  413.         end;
  414.         i := 0;
  415.     end;
  416.  
  417.     begin
  418.     ReadChar;
  419.     i := 0;
  420.     while CurrentChar <> '}' do begin
  421.         if (CurrentChar = Chr(10)) and (i > 0) then
  422.         WriteIt
  423.         else begin
  424.         Buffer[i] := CurrentChar;
  425.         Inc(i);
  426.         if i > 127 then
  427.             WriteIt;
  428.         end;
  429.  
  430.         if EndOfFile() then begin
  431.         Error("File ended in a comment");
  432.         return;
  433.         end;
  434.         ReadChar;
  435.     end;
  436.     if i > 0 then
  437.         WriteIt;
  438.     ReadChar;
  439.     end;
  440.  
  441.     Procedure DoOnOff(var Flag : Boolean);
  442.     begin
  443.     ReadChar;
  444.     if CurrentChar = '+' then
  445.         Flag := True
  446.     else if CurrentChar = '-' then
  447.         Flag := False;
  448.     end;
  449.  
  450.     Procedure DoStorage;
  451.     var
  452.     KillChar : Boolean;
  453.     begin
  454.     ReadChar;
  455.     KillChar := True;
  456.     case CurrentChar of
  457.       'X' : StandardStorage := st_external;
  458.       'P' : StandardStorage := st_private;
  459.       'N' : StandardStorage := st_internal;
  460.     else begin
  461.         Error("Unknown storage class");
  462.         KillChar := False;
  463.          end;
  464.     end;
  465.     if KillChar then
  466.         ReadChar;
  467.     end;
  468.  
  469. begin
  470.     readchar;
  471.     if currentchar = '$' then begin
  472.     repeat
  473.         readchar; { either $ or , }
  474.         Case CurrentChar of
  475.           'I' : if (NextChar = '+') or (NextChar = '-') then
  476.             DoOnOff(IOCheck)
  477.             else begin
  478.             DoInclude;
  479.             return;
  480.             end;
  481.           'A' : begin
  482.             DoASM;
  483.             return;
  484.             end;
  485.           'R' : DoOnOff(RangeCheck);
  486.           'O' : DoOnOff(IOCheck);
  487.           'S' : DoStorage;
  488.           'B' : DoOnOff(ShortCircuit);
  489.         else begin
  490.             Error("Unknown Directive");
  491.             EndComment;
  492.             return;
  493.          end;
  494.         end;
  495.         if (CurrentChar <> ',') or EndOfFile then begin
  496.         EndComment;
  497.         return;
  498.         end;
  499.     until false;
  500.     end else
  501.     EndComment;
  502. end;
  503.  
  504. Function Alpha(c : char): boolean;
  505.  
  506. {
  507.     This function answers the eternal question "is this
  508. character an alphabetic character?"  Note that _ is.
  509. }
  510.  
  511. begin
  512.     c := toupper(c);
  513.     Alpha := ((c >= 'A') and (c <= 'Z')) or (c = '_');
  514. end;
  515.  
  516. Function AlphaNumeric(c : char): boolean;
  517.  
  518. {
  519.     Is the character a letter or digit?
  520. }
  521.  
  522. begin
  523.     AlphaNumeric := Alpha(c) or isdigit(c);
  524. end;
  525.  
  526. Procedure Header;
  527.  
  528. {
  529.     This routine references all the run time library routines.
  530. One thing I like about A68k is that the only routines that are
  531. used in the assembly code end up in the object file.  Maybe all
  532. assemblers do it, but I don't know.
  533. }
  534.  
  535. begin
  536.     writeln(OutFile, "* Pascal compiler intermediate assembly program.\n\n");
  537.     writeln(OutFile, "\tSECTION\tPCQMain\n");
  538.     writeln(OutFile, "\tXREF\t_Input");
  539.     writeln(OutFile, "\tXREF\t_Output");
  540.     writeln(OutFile, "\tXREF\t_p%WriteInt");
  541.     writeln(OutFile, "\tXREF\t_p%WriteReal");
  542.     writeln(OutFile, "\tXREF\t_p%WriteChar");
  543.     writeln(OutFile, "\tXREF\t_p%WriteBool");
  544.     writeln(OutFile, "\tXREF\t_p%WriteCharray");
  545.     writeln(OutFile, "\tXREF\t_p%WriteString");
  546.     writeln(OutFile, "\tXREF\t_p%WriteLn");
  547.     writeln(OutFile, "\tXREF\t_p%ReadInt");
  548.     writeln(OutFile, "\tXREF\t_p%ReadReal");
  549.     writeln(OutFile, "\tXREF\t_p%ReadCharray");
  550.     writeln(OutFile, "\tXREF\t_p%ReadChar");
  551.     writeln(OutFile, "\tXREF\t_p%ReadString");
  552.     writeln(OutFile, "\tXREF\t_p%ReadLn");
  553.     writeln(OutFile, "\tXREF\t_p%ReadArb");
  554.     writeln(OutFile, '\tXREF\t_p%FilePtr');
  555.     writeln(OutFile, '\tXREF\t_p%Get');
  556.     writeln(OutFile, '\tXREF\t_p%Put');
  557.     writeln(OutFile, "\tXREF\t_p%dispose");
  558.     writeln(OutFile, "\tXREF\t_p%new");
  559.     writeln(OutFile, "\tXREF\t_p%Open");
  560.     writeln(OutFile, "\tXREF\t_p%OpenB");
  561.     writeln(OutFile, "\tXREF\t_p%WriteArb");
  562.     writeln(OutFile, "\tXREF\t_p%Close");
  563.     writeln(OutFile, "\tXREF\t_p%exit");
  564.     writeln(OutFile, "\tXREF\t_p%lmul");
  565.     writeln(OutFile, "\tXREF\t_p%ldiv");
  566.     writeln(OutFile, "\tXREF\t_p%lrem");
  567.     writeln(OutFile, "\tXREF\t_p%MathBase");
  568.     writeln(OutFile, '\tXREF\t_p%sin');
  569.     writeln(OutFile, '\tXREF\t_p%cos');
  570.     writeln(OutFile, '\tXREF\t_p%sqrt');
  571.     Writeln(OutFile, '\tXREF\t_p%tan');
  572.     Writeln(OutFile, '\tXREF\t_p%atn');
  573.     Writeln(OutFile, '\tXREF\t_p%ln');
  574.     Writeln(OutFile, '\tXREF\t_p%exp');
  575.     Writeln(OutFile, '\tXREF\t_p%CheckIO');
  576.     Writeln(OutFile, '\tXREF\t_p%CheckRange\n');
  577.     if mainmode then begin
  578.     if SmallInitialize then begin
  579.         Writeln(OutFile, '\tXREF\t_p%minimal_init');
  580.         Writeln(OutFile, "\tjsr\t_p%minimal_init");
  581.     end else begin
  582.         writeln(OutFile, "\tXREF\t_p%initialize");
  583.         writeln(OutFile, "\tjsr\t_p%initialize");
  584.     end;
  585.     writeln(OutFile, "\tjsr\t_MAIN");
  586.     writeln(OutFile, '\tmoveq\t#0,d0');
  587.     writeln(OutFile, "\tjsr\t_p%exit");
  588.     writeln(OutFile, "\trts");
  589.     end
  590. end;
  591.  
  592. Procedure Trailer;
  593.  
  594. {
  595.     This routine is the most important in the compiler
  596. }
  597.  
  598. begin
  599.     writeln(OutFile, "\tEND");
  600. end;
  601.  
  602. Procedure Blanks;
  603.  
  604. {
  605.     blanks() skips spaces, tabs and eoln's.  It handles
  606. comments if it comes across one.
  607. }
  608.  
  609. var
  610.     done : boolean;
  611. begin
  612.     while ((CurrentChar <= ' ') or (CurrentChar = '{')) and
  613.       (not EndOfFile()) do begin
  614.     if CurrentChar = '{' then
  615.         DoComment
  616.     else
  617.         ReadChar;
  618.     end;
  619. end;
  620.  
  621. Procedure DumpLitQ(k : Integer);
  622.  
  623. {
  624.     This procedure dumps the literal table at the end of the
  625. compilation.  Individual components are referenced as offsets to
  626. the literal label.
  627. }
  628.  
  629. var
  630.     j        : integer;
  631.     quotemode    : boolean;
  632. begin
  633.     while k < litptr do begin
  634.     write(OutFile, "\tdc.b\t");
  635.     j := 0;
  636.     quotemode := false;
  637.     while j < 40 do begin
  638.         if (ord(litq[k]) > 31) and (ord(litq[k]) <> 39) then begin
  639.         if quotemode then
  640.             write(OutFile, litq[k])
  641.         else begin
  642.             if j > 0 then
  643.             write(OutFile, ',');
  644.             write(OutFile, chr(39), litq[k]);
  645.             quotemode := true;
  646.         end;
  647.         end else begin
  648.         if quotemode then begin
  649.             write(OutFile, chr(39));
  650.             quotemode := false;
  651.         end;
  652.         if j > 0 then
  653.             write(OutFile, ',');
  654.         write(OutFile, ord(litq[k]));
  655.         if j > 32 then
  656.             j := 40
  657.         else
  658.             j := j + 3;
  659.         end;
  660.         j := j + 1;
  661.         k := k + 1;
  662.         if k >= litptr then
  663.         j := 40;
  664.     end;
  665.     if quotemode then
  666.         write(OutFile, chr(39));
  667.     writeln(OutFile);
  668.     end
  669. end;
  670.  
  671. Procedure DumpLits;
  672. begin
  673.     if LitPtr = 0 then
  674.     return;
  675.     writeln(OutFile, '\n\tSECTION\tLITS,DATA');
  676.     PrintLabel(LitLab);
  677.     DumpLitQ(0);
  678. end;
  679.  
  680. Procedure DumpIds;
  681.  
  682. {
  683.     This routine does whatever is appropriate with the various
  684. identifers.  If it's a global, it either references it or allocates
  685. space.  Similar stuff for the other ids.  When the modularity of
  686. PCQ is better defined, this routine will have to do more work.
  687. }
  688.  
  689. var
  690.     CB        : BlockPtr;
  691.     ID        : IDPtr;
  692.     TP        : TypePtr;
  693.     i        : Integer;
  694.     isodd    : boolean;
  695.     WroteSection : Boolean;
  696. begin
  697.     WroteSection := False;
  698.     isodd := false;
  699.     CB := CurrentBlock;
  700.     while CB <> nil do begin
  701.     for i := 0 to Hash_Size do begin
  702.         ID := CB^.Table[i];
  703.         while ID <> nil do begin
  704.         case ID^.Object of
  705.           global : case ID^.Storage of
  706.                 st_internal,
  707.                 st_private  : begin
  708.                         if not WroteSection then begin
  709.                         writeln(OutFile, "\n\tSECTION\tSTORAGE,BSS\n");
  710.                         WroteSection := True;
  711.                         end;
  712.                         TP := ID^.VType;
  713.                         if isodd and (TP^.Size > 1) then begin
  714.                         Writeln(OutFile, "\tCNOP\t0,2");
  715.                         isodd := False;
  716.                         end;
  717.                         if ID^.Storage <> st_private then
  718.                         Writeln(OutFile,"\tXDEF\t_", ID^.Name);
  719.                         Write(OutFile, '_', ID^.Name);
  720.                         Writeln(OutFile, "\tds.b\t", TP^.Size);
  721.                         if odd(TP^.Size) then
  722.                         isodd := not isodd;
  723.                       end;
  724.                end;
  725.           proc,
  726.           func  : if ID^.Storage = st_forward then
  727.                 Writeln(ID^.Name, ' was never defined.');
  728.         end;
  729.         ID := ID^.Next;
  730.         end;
  731.     end;
  732.     CB := CB^.Previous;
  733.     end;
  734. end;
  735.  
  736. Procedure DumpRefs;
  737.  
  738. {
  739.     This routine makes all the external references necessary.
  740. }
  741.  
  742. var
  743.     CB        : BlockPtr;
  744.     ID        : IDPtr;
  745.     i        : Integer;
  746. begin
  747.     writeln(OutFile);
  748.     CB := CurrentBlock;
  749.     while CB <> nil do begin
  750.     for i := 0 to Hash_Size do begin
  751.         ID := CB^.Table[i];
  752.         while ID <> nil do begin
  753.         if ID^.Storage = st_external then
  754.             writeln(OutFile, "\tXREF\t_", ID^.Name);
  755.         ID := ID^.Next;
  756.         end;
  757.     end;
  758.     CB := CB^.Previous;
  759.     end
  760. end;
  761.  
  762. Procedure SearchReserved;
  763.  
  764. {
  765.     This just does a binary chop search of the list of reserved
  766. words.
  767. }
  768.  
  769. var
  770.     top,
  771.     middle,
  772.     bottom    : Symbols;
  773.     compare    : Short;
  774. begin
  775.     Bottom := And1;
  776.     Top := LastReserved;
  777.     while Bottom <= Top do begin
  778.     middle := Symbols((Byte(bottom) + Byte(top)) div 2);
  779.     Compare := stricmp(Reserved[Middle], SymText);
  780.     if Compare = 0 then begin
  781.         CurrSym := Middle;
  782.         Return;
  783.     end else if Compare < 0 then
  784.         Bottom := Succ(Middle)
  785.     else
  786.         Top := Pred(Middle);
  787.     end;
  788.     CurrSym := Ident1;
  789. end;
  790.  
  791. Procedure ReadWord;
  792.  
  793. {
  794.     This reads a Pascal identifier into symtext.
  795. }
  796.  
  797. var
  798.     ptr        : string;
  799. begin
  800.     ptr := symtext;
  801.     repeat
  802.     Ptr^ := CurrentChar;
  803.     Ptr := String(Integer(Ptr) + 1);
  804.     ReadChar;
  805.     until not AlphaNumeric(CurrentChar);
  806.     Ptr^ := chr(0);
  807.     SearchReserved;
  808. end;
  809.  
  810. Function DigVal(c : Char) : Integer;
  811. begin
  812.     DigVal := Ord(c) - Ord('0');
  813. end;
  814.  
  815. Procedure ReadNumber;
  816.  
  817. {
  818.     This routine reads a literal integer.  Note that _ can be used.
  819. }
  820.  
  821. var
  822.     Divider : Real;
  823.     Fraction : Real;
  824. begin
  825.     SymLoc := 0;
  826.     While isdigit(CurrentChar) do begin
  827.     SymLoc := (SymLoc * 10) + DigVal(CurrentChar);
  828.     ReadChar;
  829.     if CurrentChar = '_' then
  830.         ReadChar;
  831.     end;
  832.     CurrSym := Numeral1;
  833.     if (CurrentChar = '.') and isdigit(NextChar()) then begin { It's real! }
  834.     ReadChar; { skip the . }
  835.     RealValue := Float(SymLoc);
  836.     Divider := 1.0;
  837.     Fraction := 0.0;
  838.     while isdigit(CurrentChar) do begin
  839.         Fraction := Fraction * 10.0 + Float(DigVal(CurrentChar));
  840.         Divider := Divider * 10.0;
  841.         ReadChar;
  842.     end;
  843.     RealValue := RealValue + Fraction / Divider;
  844.     CurrSym := RealNumeral1;
  845.     end;
  846. end;
  847.  
  848. Procedure ReadHex;
  849.  
  850. {
  851.     readhex() reads a hexadecimal number.
  852. }
  853.  
  854. var
  855.     rc    : integer;
  856.     Count : Short;
  857. begin
  858.     ReadChar;
  859.     symloc := 0;
  860.     Count := 0;
  861.     rc := ord(toupper(currentchar));
  862.     while isdigit(currentchar) or
  863.       ((rc >= ord('A')) and (rc <= ord('F'))) do begin
  864.     Inc(Count);
  865.     SymLoc := SymLoc shl 4;
  866.     if isdigit(currentchar) then
  867.         symloc := symloc + ord(currentchar) - ord('0')
  868.     else
  869.         symloc := symloc + rc - ord('A') + 10;
  870.     ReadChar;
  871.     rc := ord(toupper(currentchar));
  872.     end;
  873.  
  874.     if Count = 0 then
  875.     Error("No hexadecimal digits")
  876.     else if Count > 8 then
  877.     Error("Constant out of range (more than 32 bits)");
  878.  
  879.     currsym := numeral1;
  880. end;
  881.  
  882.  
  883. Procedure ReadBinary;
  884. {
  885.     Reads a binary number, of the form %[0|1]*
  886. }
  887. var
  888.     Count : Short;
  889. begin
  890.     ReadChar; { Read past the % }
  891.     SymLoc := 0;
  892.     Count := 0;
  893.     while (CurrentChar = '0') or (CurrentChar = '1') do begin
  894.     Inc(Count);
  895.     SymLoc := (SymLoc shl 1) + DigVal(CurrentChar);
  896.     ReadChar;
  897.     end;
  898.  
  899.     if Count = 0 then
  900.     Error("No binary digits")
  901.     else if Count > 32 then
  902.     Error("Constant out of range (more than 32 bits)");
  903.  
  904.     CurrSym := Numeral1;
  905. end;
  906.  
  907. {
  908. Procedure ReadString;
  909. var
  910.     Delim : Char;
  911. begin
  912.     InStringLength := 0;
  913.     Delim := CurrentChar;
  914.     ReadChar;
  915.     repeat
  916.     if CurrentChar = Delim then begin
  917.         ReadChar;
  918.         if (CurrentChar = Delim) and (Delim = '\'') then begin
  919.         Insert('\'');
  920.         ReadChar;
  921.         end else
  922.         Quit := True;
  923.     end else if CurrentChar = '#' then begin
  924.         ReadChar;
  925.         case CurrentChar of
  926.           '0'..'9'  : ReadNumber;
  927.           '$'    : ReadHex;
  928.           '%'    : ReadBinary;
  929.         else begin
  930.              Error("Expecting an integer");
  931.              SymLoc := 0;
  932.              CurrSym := Numeral1;
  933.          end;
  934.         end;
  935.         if CurrSym <> Numeral1 then
  936.         Error("Expecting an integer");
  937.         if SymLoc > 255 then
  938.         Error("Constant out of range");
  939.         Insert(Chr(SymLoc));
  940.     end else if CurrentChar = Chr(10) then begin
  941.         Error("String exceeds line");
  942.         Quit := True;
  943.     end else if CurrentChar = '\\' then begin
  944.         ReadChar;
  945.         case CurrentChar of
  946.           'n' : Insert(Chr(10));
  947.           't' : Insert(Chr(9));
  948.           '0' : Insert(Chr(0));
  949.           'b' : Insert(Chr(8));
  950.           'e' : Insert(Chr(27));
  951.           'c' : Insert(Chr($9B));
  952.           'a' : Insert(Chr(7));
  953.           'f' : Insert(Chr(12));
  954.           'r' : Insert(Chr(13));
  955.           'v' : Insert(Chr(11));
  956.         else
  957.         Insert(CurrentChar);
  958.         end;
  959.         ReadChar;
  960.     end else begin
  961.         Insert(CurrentChar);
  962.         ReadChar;
  963.     end;
  964.     until Quit;
  965.     if InStringLength = 1 then begin
  966.     SymLoc := InString[0];
  967.     CurrSym := Char1;
  968.     end else if Delim = '"' then
  969.     CurrSym := Quote1
  970.     else
  971.     CurrSym := Apostrophe1;
  972. end;
  973. }
  974.  
  975. Procedure WriteHex(num : integer);
  976.  
  977. {
  978.     This writes full 32 bit hexadecimal numbers.
  979. }
  980.  
  981. var
  982.     numary  : array [1..8] of char;
  983.     pos     : integer;
  984.     ch      : Short;
  985. begin
  986.     pos := 8;
  987.     while (num <> 0) and (pos > 0) do begin
  988.     ch := num and 15;
  989.     if ch < 10 then
  990.         numary[pos] := chr(ch + ord('0'))
  991.     else
  992.         numary[pos] := chr(ch + ord('A') - 10);
  993.     pos := pos - 1;
  994.     num := num shr 4;
  995.     end;
  996.     if pos = 8 then begin
  997.     pos := 7;
  998.     numary[8] := '0';
  999.     end;
  1000.     write(OutFile, '$');
  1001.     for num := pos + 1 to 8 do
  1002.     write(OutFile, numary[num]);
  1003. end;
  1004.  
  1005. Procedure NextSymbol;
  1006.  
  1007. {
  1008.     This is the workhorse lexical analysis routine.  It sets
  1009. currsym to the appropriate symbol number, sets symtext equal to
  1010. whatever identifier is read, and symloc to the value of a literal
  1011. integer.
  1012. }
  1013.  
  1014. begin
  1015.     Blanks;
  1016.     ErrorPtr := EQEnd;
  1017.     if EndOfFile then begin
  1018.     CurrentChar := Chr(0);
  1019.     CurrSym := EndText1; { I don't think this routine is ever hit }
  1020.     Return;
  1021.     end;
  1022.     if Alpha(CurrentChar) then
  1023.     readword
  1024.     else if isdigit(currentchar) then
  1025.     readnumber
  1026.     else begin
  1027.     case CurrentChar of
  1028.       '[' : begin
  1029.             CurrSym:= leftbrack1;
  1030.             ReadChar;
  1031.         end;
  1032.       ']' : begin
  1033.             CurrSym:= rightbrack1;
  1034.             ReadChar;
  1035.         end;
  1036.       '(' : begin
  1037.             CurrSym:= leftparent1;
  1038.             ReadChar;
  1039.         end;
  1040.       ')' : begin
  1041.             CurrSym:= rightparent1;
  1042.             ReadChar;
  1043.         end;
  1044.       '+' : begin
  1045.             CurrSym := plus1;
  1046.             ReadChar;
  1047.         end;
  1048.       '-' : begin
  1049.             CurrSym := minus1;
  1050.             ReadChar;
  1051.         end;
  1052.       '*' : begin
  1053.             CurrSym:= asterisk1;
  1054.             ReadChar;
  1055.         end;
  1056.       '/' : begin
  1057.             CurrSym := RealDiv1;
  1058.             ReadChar;
  1059.         end;
  1060.       '<' : begin
  1061.             ReadChar;
  1062.             if CurrentChar = '=' then begin
  1063.             CurrSym := notgreater1;
  1064.             ReadChar;
  1065.             end else if currentchar = '>' then begin
  1066.             CurrSym := notequal1;
  1067.             ReadChar;
  1068.             end else
  1069.             CurrSym:= less1;
  1070.         end;
  1071.       '=' : begin
  1072.             CurrSym:= equal1;
  1073.             ReadChar;
  1074.         end;
  1075.       '>' : begin
  1076.             ReadChar;
  1077.             if CurrentChar = '=' then begin
  1078.             CurrSym:= notless1;
  1079.             ReadChar;
  1080.             end else
  1081.             CurrSym:= greater1;
  1082.         end;
  1083.       ':' : begin
  1084.             ReadChar;
  1085.             if CurrentChar = '=' then begin
  1086.             CurrSym:= Becomes1;
  1087.             ReadChar;
  1088.             end else
  1089.             CurrSym:= colon1;
  1090.         end;
  1091.       ',' : begin
  1092.             CurrSym:= comma1;
  1093.             ReadChar;    
  1094.         end;
  1095.       '.' : begin
  1096.             ReadChar;
  1097.             if CurrentChar = '.' then begin
  1098.             CurrSym:= DotDot1;
  1099.             ReadChar;
  1100.             end else
  1101.             CurrSym:= period1;
  1102.         end;
  1103.       ';' : begin
  1104.             CurrSym:= semicolon1;
  1105.             ReadChar;
  1106.         end;
  1107.       '\'': begin
  1108.             CurrSym:= apostrophe1;
  1109.             ReadChar;
  1110.         end;
  1111.       '"' : begin
  1112.             CurrSym:= quote1;
  1113.             ReadChar;
  1114.         end;
  1115.       '^' : begin
  1116.             CurrSym:= carat1;
  1117.             ReadChar;
  1118.         end;
  1119.       '@' : begin
  1120.             CurrSym := At1;
  1121.             ReadChar;
  1122.         end;
  1123.       '$' : ReadHex;
  1124.       '%' : ReadBinary;
  1125.      '\0' : CurrSym := EndText1;
  1126.     else begin
  1127.         Error("Unknown symbol.");
  1128.         ReadChar;
  1129.          end;
  1130.     end; { Case }
  1131.     end; { Else }
  1132. end;
  1133.